use hyper::{
    body,
    service::{make_service_fn, service_fn},
};
use hyper::{body::to_bytes, Body, Request, Response, Server};
use regex::Regex;
use serde::{
    de::{DeserializeOwned, Error},
    Deserialize, Serialize,
};
use std::{
    borrow::BorrowMut,
    collections::{HashMap, HashSet},
    convert::{Infallible, TryInto},
    fs::File,
    io::{Read, Write},
    string::FromUtf8Error,
    vec,
};
use std::{fmt::Debug, net::SocketAddr};

#[derive(Serialize, Deserialize, Debug)]
struct Person {
    name: String,
}

struct App {}

impl App {
    pub fn new() -> Self {
        // Construct our SocketAddr to listen on...

        App {}
    }

    pub async fn run(self) -> Self {
        let addr = SocketAddr::from(([127, 0, 0, 1], 3000));

        // And a MakeService to handle each connection...
        let make_service =
            make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(App::handle)) });

        // Then bind and serve...
        let server = Server::bind(&addr).serve(make_service);

        // And run forever...
        if let Err(e) = server.await {
            eprintln!("server error: {}", e);
        }
        self
    }

    async fn handle(req: Request<Body>) -> Result<Response<Body>, Infallible> {
        println!("{:#?}", req);

        let mut req = HttpRequest::from(req).await;
        // let ret = format!("body json:{:#?}", req.json::<Person>().await.unwrap());

        let a = App::dispatch(req).await;

        Ok(Response::new(Body::from("test")))
    }

    async fn dispatch(mut req: HttpRequest) -> String {
        if let Some(header_value) = req.req.headers().get("content-type") {
            let header_value = header_value.to_str().unwrap().to_string();
            let v: Vec<&str> = header_value.splitn(2, ";").collect();
            let content_type = v.get(0).unwrap_or(&"");
            println!("content type:{}", content_type);

            if content_type == &"multipart/form-data" {
                let form = Self::parse_form_data(&req).await;
                if !form.is_empty() {
                    req.form = Some(form);
                }

                println!("password:{:?}", req.form("password"));
            } else if content_type == &"application/json" {
                let data = req.json::<Person>().await;
                println!("body:{:#?}", data);
            }
        }
        String::new()
    }

    #[inline]
    async fn parse_form_data(req: &HttpRequest) -> Vec<FormData> {
        let body = req.body.as_ref().unwrap();

        let header_value = req.req.headers().get("content-type").unwrap();
        let header_value = header_value.to_str().unwrap().to_string();
        let v: Vec<&str> = header_value.splitn(2, ";").collect();
        // let content_type = v.get(0).unwrap();

        let boundary: Vec<&str> = v.get(1).unwrap().splitn(2, "=").collect();
        let boundary = boundary.get(1).unwrap();
        let boundary = boundary.as_bytes();
        let data = body;

        let mut pos = vec![];
        for i in 0..data.len() {
            // 定位到每個分割字符串的行末

            // 跳过不是换行的字符
            // 如果长度不足 boundary 长度，防止第 3 个条件中数组越界
            // 如果换行往前获取 boundary 长度的字节来对比，不相等的话就跳过
            if *data.get(i).unwrap() != b'\n'
                || i <= boundary.len() + 2
                || data[i - boundary.len() - 1..=i - 2].ne(boundary)
            {
                continue;
            }

            // println!(
            //     "数据：{},{:?}",
            //     i,
            //     String::from_utf8(data[i - boundary.len() - 1..=i - 2].to_vec()).unwrap()
            // );

            pos.push(i + 1);
        }
        // println!("pos:{:?}", pos);

        // 把数据按照 boundary 分段, 把每一段数据的起始坐标保存在数组中，数据取值范围：[start, end)
        let mut part_pos = vec![];
        for i in 0..pos.len() {
            let start;
            let end;
            if i == 0 {
                start = pos[i];
                // 2 2 2 分别是 增加的2个-，空行(\r\n),以及分段本身定位在\n后面 所以再去掉下一个定位之前的 \r\n
                /*
                例如下面的 form-data
                pub mod service;

                ----------------------------750159610116247640532361
                Content-Disposition: form-data; name="name"
                */
                end = pos[i + 1] - boundary.len() - 2 - 2 - 2;
            } else if i == pos.len() - 1 {
                start = pos[pos.len() - 1];

                // 多出的一个2  是因为内容最后追加了 2 个 - 符号
                end = data.len() - boundary.len() - 2 - 2 - 2 - 2;
            } else {
                start = pos[i];
                end = pos[i + 1] - boundary.len() - 2 - 2 - 2;
            }

            part_pos.push((start, end));
        }

        let mut data_pos = vec![];
        // 处理每一段那种的 类型信息和内容  以 \r\n\r\n 分割
        for (start, end) in part_pos {
            // println!(
            //     "data:{:?}",
            //     String::from_utf8(data[start..end].to_vec()).unwrap()
            // );
            for i in start..end {
                if *data.get(i).unwrap() != b'\n' || data[i - 3..=i].ne(b"\r\n\r\n") {
                    continue;
                }
                data_pos.push((start, i - 3, i + 1, end));
                break;
            }
        }

        // self.form_data = Some(data_pos);

        // println!("data_pos:{:#?}", data_pos);

        let re = Regex::new(
            r#"Content-Disposition:.*?; name=['"](.+?)['"](; filename=['"](.+?)['"]){0,1}([\s\S]*?Content-Type: ([^\r\n]*)){0,1}"#,
        )
        .unwrap();

        let mut form_datas = vec![];
        for (a1, a2, b1, b2) in data_pos {
            let text = String::from_utf8(data[a1..a2].to_vec()).unwrap();
            println!("data1:{}", text);

            if let Some(cap) = re.captures_iter(&text).next() {
                let name = match &cap.get(1) {
                    Some(v) => {
                        if v.as_str().is_empty() {
                            continue;
                        } else {
                            Some(v.as_str().to_string())
                        }
                    }
                    None => continue,
                };

                let filename = match &cap.get(3) {
                    Some(v) => Some(v.as_str().to_string()),
                    None => None,
                };
                let content_type = match &cap.get(5) {
                    Some(v) => Some(v.as_str().to_string()),
                    None => None,
                };

                let form_data = FormData {
                    name: name.unwrap_or("".to_string()),
                    content_type,
                    filename,
                    pos: (b1, b2),
                    data: vec![],
                };
                form_datas.push(form_data);
            }
        }

        form_datas
    }
}

#[derive(Debug, Clone)]
struct FormData {
    name: String,
    content_type: Option<String>,
    filename: Option<String>,
    pos: (usize, usize), //记录对应的数据位置
    data: Vec<u8>,
}

impl FormData {
    pub fn get_bytes(self) -> Vec<u8> {
        self.data
    }

    pub fn get_text(self) -> Result<String, String> {
        match String::from_utf8(self.data) {
            Ok(v) => Ok(v),
            Err(e) => Err(format!("{}", e)),
        }
    }
}

struct HttpRequest {
    req: Request<Body>,
    form: Option<Vec<FormData>>,
    body: Option<Vec<u8>>,
    query: Option<HashMap<String, String>>,
}

impl HttpRequest {
    pub async fn from(mut req: Request<Body>) -> Self {
        let body = if let Ok(body) = to_bytes(req.body_mut()).await {
            Some(body.to_vec())
        } else {
            None
        };

        let path = req.uri().path();
        let query = req.uri().query();

        let path = String::from(path).to_lowercase();
        let path: Vec<&str> = path.split("/").collect();

        let query = query.unwrap_or("");

        let query = String::from(query).to_lowercase();
        let kvs: Vec<&str> = if query.len() > 0 {
            query.split("&").collect()
        } else {
            vec![]
        };
        let mut query = HashMap::new();

        for kv in kvs {
            let kv: Vec<&str> = kv.split("=").collect();
            query.insert(
                kv.get(0).unwrap_or(&"").to_string(),
                kv.get(1).unwrap_or(&"").to_string(),
            );
        }
        println!("path:{:#?}", path);
        println!("query:{:#?}", query);

        HttpRequest {
            req,
            form: None,
            body,
            query: Some(query),
        }
    }

    pub async fn json<T>(self) -> Result<T, serde_json::Error>
    where
        T: DeserializeOwned + Debug,
    {
        let body = String::from_utf8(self.body.unwrap()).unwrap();
        serde_json::from_str(&body)
    }

    // 根据 name 获取数据
    fn data(&self, name: &str) -> Option<FormData> {
        if self.form.is_none() || self.form.as_ref().unwrap().is_empty() {
            return None;
        }

        for v in self.form.as_ref().unwrap() {
            if v.name.eq(name) {
                let mut v = v.clone();
                v.data = self.body.as_ref().unwrap()[v.pos.0..v.pos.1].to_vec();
                return Some(v);
            }
        }

        None
    }

    pub fn form(&self, name: &str) -> String {
        if let Some(v) = self.data(name) {
            if v.filename.is_some() {
                return String::new();
            }
            return v.get_text().unwrap_or("".to_string());
        }

        String::new()
    }

    pub fn file(&self, name: &str) -> Option<FormData> {
        if let Some(v) = self.data(name) {
            if v.filename.is_none() {
                return None;
            }
            return Some(v);
        }
        None
    }
}

#[tokio::main]
async fn main() {
    App::new().run().await;
}
